/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dynaspring.support;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.core.GenericCollectionTypeResolver;

/**
 * Adaptation of Spring's SetFactoryBean to allow multiple source sets.
 * 
 * @author Alessio Stalla (original Spring code by Juergen Hoeller)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class SetFactoryBean extends AbstractFactoryBean<Set> {

	private List<Set> sourceSets;

	private Class targetSetClass = HashSet.class;

	/**
	 * Set the source Sets
	 */
	public void setSourceSets(List<Set> sourceSets) {
		this.sourceSets = sourceSets;
	}

	/**
	 * Set the class to use for the target Set. Can be populated with a fully
	 * qualified class name when defined in a Spring application context.
	 * <p>
	 * Default is a <code>java.util.HashSet</code>.
	 * 
	 * @see java.util.HashSet
	 */
	public void setTargetSetClass(Class targetSetClass) {
		if (targetSetClass == null) {
			throw new IllegalArgumentException("'targetSetClass' must not be null");
		}
		if (!Set.class.isAssignableFrom(targetSetClass)) {
			throw new IllegalArgumentException("'targetSetClass' must implement [java.util.List]");
		}
		this.targetSetClass = targetSetClass;
	}

	public Class getObjectType() {
		return Set.class;
	}

	protected Set createInstance() {
		if (this.sourceSets == null) {
			throw new IllegalArgumentException("'sourceSets' is required");
		}
		Set result = (Set) BeanUtils.instantiateClass(this.targetSetClass);
		Class valueType = GenericCollectionTypeResolver.getCollectionType(this.targetSetClass);
		TypeConverter converter = getBeanTypeConverter();
		for(Set sourceSet : sourceSets) {
			if(valueType != null) {
				for(Iterator it = sourceSet.iterator(); it.hasNext();) {
					result.add(converter.convertIfNecessary(it.next(), valueType));
				}
			} else {
				result.addAll(sourceSet);
			}
		}
		return result;
	}

}